float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 InverseView;
float4x4 InverseProjection;

float3 LightPosition;
float3 LightColor; 

float2 HalfPixel;

float LightRadius;

bool Shadows;

texture NormalMap;
texture DepthMap;
texture ShadowMap;

sampler depthSampler = sampler_state
{
    Texture = (DepthMap);
    AddressU = CLAMP;
    AddressV = CLAMP;
    MagFilter = POINT;
    MinFilter = POINT;
    Mipfilter = POINT;
};

sampler normalSampler = sampler_state
{
    Texture = (NormalMap);
    AddressU = CLAMP;
    AddressV = CLAMP;
    MagFilter = POINT;
    MinFilter = POINT;
    Mipfilter = POINT;
};

sampler shadowSampler = sampler_state
{
    Texture = (ShadowMap);
    AddressU = CLAMP;
    AddressV = CLAMP;
    MagFilter = POINT;
    MinFilter = POINT;
    Mipfilter = POINT;
};

struct VertexShaderInput
{
    float3 Position			: POSITION0;
};

struct VertexShaderOutput
{
    float4 Position			: POSITION0;
    float4 ScreenPosition	: TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;
    float4 worldPosition = mul(float4(input.Position,1), World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
    output.ScreenPosition = output.Position;
    return output;
}

float3 getPosition(in float2 uv)
{
	float z = tex2D(depthSampler, uv).r;
	float x = uv.x * 2.0 - 1.0;
	float y = (1 - uv.y) * 2.0 - 1.0;
	float4 vpos = float4(x, y, z, 1.0f);
	vpos = mul(vpos, InverseProjection);
	return vpos / vpos.w;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    //obtain screen position
    input.ScreenPosition.xy /= input.ScreenPosition.w;

    //obtain textureCoordinates corresponding to the current pixel
    //the screen coordinates are in [-1,1]*[1,-1]
    //the texture coordinates need to be in [0,1]*[0,1]
    float2 texCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);

    //allign texels to pixels
    texCoord -= HalfPixel;

    //get normal data from the normalMap
    float4 normalData = tex2D(normalSampler,texCoord);

    //tranform normal back into [-1,1] range
    float3 normal = 2.0f * normalData.xyz - 1.0f;

    //compute view-space position
	float3 position = getPosition(texCoord);

	if (Shadows)
	{
		// position in world
		float4 positionWS = mul(float4(position.xyz, 1.0), InverseView);

        float3 pixelDif = LightPosition - positionWS.xyz;
        float3 texDir = normalize(pixelDif);
        float lightDepth = texCUBE(shadowSampler, texDir).r;

        clip( lightDepth - length(pixelDif) + 0.2 );
	}


    // light position in view space
	float4 lPos = mul(float4(LightPosition, 1.0), View);

	// surface to light vector
    float3 lightVector = lPos.xyz - position.xyz;
    //return length(lightVector) / 10.0;

    //compute attenuation based on distance - linear attenuation
    float attenuation = saturate(1.0f - length(lightVector)/LightRadius);

    //normalize light vector
    lightVector = normalize(lightVector); 

    //compute diffuse light
    float NdL = max(0,dot(normal,lightVector));
    float4 diffuseLight = float4(NdL * LightColor.rgb, 1.0);

    //take into account attenuation and lightIntensity.
    return attenuation * diffuseLight;
}

technique Light
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
